#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <limits.h>


#define NTHREADS 8 //Numero de threads que serao executadas ao mesmo tempo
#define precisaoPI 100000000 //Numero de pontos que serao utilizados na estimacao de PI

const unsigned int aleatorio1 = 1664525, aleatorio2 = 1013904223;

typedef struct //Estrutura que salva o numero de pontos dentro do quadrado e dentro do ciruculo
{
    int pontosCirculo;
    int pontosQuadrado;
} pontoStruct;

pontoStruct nPontos[NTHREADS]; //vetor global da estrutura que conta o numero de pontos



unsigned int funcaoRandomica(unsigned int x)
{
    return x*aleatorio1+aleatorio2;
}


void *adicionaPontos(void *param){

    int i;
    double x1;
    double y1;
    unsigned int x = (double)rand();
    int nThread = *((int *)param);
    //printf("%u \n", x);


    for (i = 0; i < precisaoPI/NTHREADS; i++){ //Adiciona os pontos no quadrado e no circulo

        x = funcaoRandomica(x); //Encontra um numero aleatorio para x e y entre 0 e 1
        x1 = (double)x/UINT_MAX;
        x = funcaoRandomica(x);
        y1 = (double)x/UINT_MAX;


        if((x1*x1) + (y1*y1) <= 1){ //Verifica se o ponto esta dentro do circulo
            nPontos[nThread].pontosCirculo++; //Incrementa o contador de pontos do circulo
        }
        nPontos[nThread].pontosQuadrado++; //Incrementa o contador de pontos do quadrado

    }

    pthread_exit(0);

}


int main (int argc, char *argv[]){

    double valorPi = 0; //valor final de PI
    pthread_t threadPI[NTHREADS];  // vetor de threads a ser utilizado
    srand(time(NULL)); //Inicializa a funcao randomica
    double totalPontosCirculo = 0;
    double totalPontosQuadrado = 0;

    int i;
    for (i = 0; i< NTHREADS ; i++){
            nPontos[i].pontosCirculo = 0; //Inicializa os contadores de pontos da estrutura
            nPontos[i].pontosQuadrado = 0;
    }
    for (i = 0; i< NTHREADS ; i++){
                //Cria as threads do vetor com a funcao de adicionar pontos e a o numero do vetor do contador de pontos
                pthread_create (&threadPI[i], NULL, adicionaPontos, &i);
    }
    for (i = 0; i< NTHREADS ; i++){ //Espera todas as threads concluirem
                pthread_join (threadPI[i], NULL);
    }
    for (i = 0; i< NTHREADS ; i++){ //Junta todos os pontos de todas as threads
            totalPontosCirculo = totalPontosCirculo + nPontos[i].pontosCirculo;
            totalPontosQuadrado = totalPontosQuadrado + nPontos[i].pontosQuadrado;
    }

    //Calcula o valor do PI, multiplicando os pontos do circulo por 4 e dividindo tudo pelos pontos do quadrado
    valorPi = (4*totalPontosCirculo)/(totalPontosQuadrado);

    printf("%.6lf\n", valorPi);//Imprime o valor de PI com 6 casas decimais

    return 0;
}
